package com.dhms.uikit.media

import android.content.Intent
import android.database.Cursor
import android.graphics.Bitmap
import android.media.MediaPlayer
import android.media.ThumbnailUtils
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.provider.OpenableColumns
import android.util.Log
import android.util.Size
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.MediaController
import android.widget.Toast
import androidx.core.net.toFile
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import coil.load
import com.dhms.uikit.R
import com.dhms.uikit.databinding.FragmentPreviewBinding
import com.dhms.uikit.isLocalResource
import com.dhms.uikit.media.MediaActivity.Companion.BROADCAST_FILE_PATH_KEY
import com.dhms.uikit.media.MediaActivity.Companion.BROADCAST_FILE_THUMBNAIL_KEY
import com.dhms.uikit.media.MediaActivity.Companion.BROADCAST_FILE_TYPE_KEY
import kotlinx.coroutines.launch
import java.io.File
import java.io.FileOutputStream

class PreviewFragment(
    private val mediaItem: MediaItem? = null,
) : Fragment() {

    private var _binding: FragmentPreviewBinding? = null
    private val binding get() = _binding!!

    private lateinit var currentMedia: MediaItem

    private var videoThumbnail: Uri? = null
    private var isFromCameraFragment = false

    private lateinit var mediaPlayer: MediaPlayer
    private lateinit var mediaController: MediaController

    private var isVideoPrepared = false

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentPreviewBinding.inflate(inflater, container, false)

        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.lifecycleOwner = viewLifecycleOwner

        currentMedia = (mediaItem ?: (requireActivity() as MediaActivity).currentMedia)!!
        isFromCameraFragment = mediaItem == null

        showPreview()

        setBtnClickListener()
    }

    private fun setBtnClickListener() {
        binding.playBtn.setOnClickListener {
            if (currentMedia.type == MediaType.VIDEO) {
                binding.photoViewer.visibility = View.GONE
                if (!this::mediaController.isInitialized) {
                    mediaController = MediaController(requireContext())
                    binding.videoViewer.setMediaController(mediaController)
                }
                if (!isVideoPrepared) {
                    binding.isLoading = true
                }
                binding.isFailed = false
                binding.videoViewer.start()
            } else if (currentMedia.type == MediaType.AUDIO) {
                if (!this::mediaPlayer.isInitialized) {
                    Toast.makeText(requireContext(), "加载中请稍后...", Toast.LENGTH_SHORT).show()
                    return@setOnClickListener
                }
                mediaPlayer.start()
                binding.audioViewer.start()
                binding.audioPlaceholder.visibility = View.VISIBLE
            }
            it.visibility = View.GONE
        }

        if (isFromCameraFragment) {
            binding.mediaCancel.visibility = View.VISIBLE
            binding.mediaConfirm.visibility = View.VISIBLE
            binding.mediaCancel.setOnClickListener {
                findNavController().navigateUp()
            }
            binding.mediaConfirm.setOnClickListener {
                val intent =
                    Intent(MediaActivity.BROADCAST_CREATE_ACTION + (activity as MediaActivity).viewId)
                intent.putExtra(BROADCAST_FILE_PATH_KEY, currentMedia.file)
                intent.putExtra(BROADCAST_FILE_TYPE_KEY, currentMedia.type)
                intent.putExtra(BROADCAST_FILE_THUMBNAIL_KEY, videoThumbnail)
                activity?.sendBroadcast(intent)
                (activity as MediaActivity).finishActivity()
            }
        }
    }

    private fun showPreview() {
        when (currentMedia.type) {
            MediaType.PHOTO -> showPhoto()
            MediaType.VIDEO -> prepareToShowVideo()
            MediaType.AUDIO -> prepareToPlayAudio()
        }
    }

    private fun prepareToShowVideo() {
        // show the thumbnail
        binding.photoViewer.visibility = View.VISIBLE
        binding.photoViewer.load(currentMedia.thumbnail)

        showVideo(currentMedia.file)

//        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
//            showVideo(currentMedia.file)
//        } else {
//            // force MediaScanner to re-scan the media file.
//            val path = getAbsolutePathFromUri(currentMedia.file) ?: return
//            MediaScannerConnection.scanFile(
//                context, arrayOf(path), null
//            ) { _, uri ->
//                // playback video on main thread with VideoView
//                if (uri != null) {
//                    lifecycleScope.launch {
//                        showVideo(uri)
//                    }
//                }
//            }
//        }
    }

    private fun prepareToPlayAudio() {
        binding.isLoading = true
        Thread {
            try {
                mediaPlayer = MediaPlayer.create(requireContext(), currentMedia.file)
                lifecycleScope.launch {
                    binding.isLoading = false
                    binding.isFailed = false
                    binding.audioViewer.visibility = View.VISIBLE
                    binding.playBtn.visibility = View.VISIBLE
                    binding.audioViewer.timeDuration = mediaPlayer.duration / 1000
                }
                mediaPlayer.setOnCompletionListener {
                    lifecycleScope.launch {
                        binding.playBtn.visibility = View.VISIBLE
                        binding.audioPlaceholder.visibility = View.GONE
                    }
                }
            } catch (e: Exception) {
                Log.e(TAG, "Failed to load the audio ${currentMedia.file}.", e)
                binding.isLoading = false
                binding.isFailed = true
            }
        }.start()
    }

    private fun showPhoto() {
        binding.photoViewer.visibility = View.VISIBLE
        binding.photoViewer.load(currentMedia.file) {
            error(R.drawable.img_photo_placeholder)
        }
    }

    private fun showVideo(uri: Uri) {
//        val fileSize = getFileSizeFromUri(uri)
//        if (fileSize == null || fileSize <= 0) {
//            Log.e(TAG, "Failed to get recorded file size, could not be played!")
////            return
//        }
        if (!isFromCameraFragment) {
            binding.playBtn.visibility = View.VISIBLE
        }

        binding.videoViewer.visibility = View.VISIBLE
//        val filePath = getAbsolutePathFromUri(uri) ?: return
//        val fileInfo = "FileSize: $fileSize\n $filePath"
//        Log.i(TAG, fileInfo)

        // 如果是本地资源则生成缩略图
        if (isLocalResource(uri)) {
            saveThumbnail(uri)
        }

        binding.videoViewer.apply {
            setVideoURI(uri)
            requestFocus()
            setOnPreparedListener {
                binding.isLoading = false
                binding.isFailed = false
                isVideoPrepared = true
            }
            setOnErrorListener { mp: MediaPlayer, what: Int, extra: Int ->
                Log.e(TAG, "Failed to load the video ${currentMedia.file}. what:$what extra:$extra")
                binding.isLoading = false
                binding.isFailed = true
                true
            }
            setOnCompletionListener {
                binding.playBtn.visibility = View.VISIBLE
            }
        }
        if (isFromCameraFragment) {
            binding.isLoading = true
            binding.isFailed = false
            binding.videoViewer.start()
        }
    }

    /**
     * A helper function to get the captured file location.
     */
    private fun getAbsolutePathFromUri(contentUri: Uri): String? {
        var cursor: Cursor? = null
        return try {
            cursor = requireContext()
                .contentResolver
                .query(contentUri, arrayOf(MediaStore.Images.Media.DATA), null, null, null)
            if (cursor == null) {
                return null
            }
            val columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
            cursor.moveToFirst()
            cursor.getString(columnIndex)
        } catch (e: RuntimeException) {
            Log.e(
                TAG, String.format(
                    "Failed in getting absolute path for Uri %s with Exception %s",
                    contentUri.toString(), e.toString()
                )
            )
            null
        } finally {
            cursor?.close()
        }
    }

    /**
     * A helper function to retrieve the captured file size.
     */
    private fun getFileSizeFromUri(contentUri: Uri): Long? {
        val cursor = requireContext()
            .contentResolver
            .query(contentUri, null, null, null, null)
            ?: return null

        val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)
        cursor.moveToFirst()

        cursor.use {
            return it.getLong(sizeIndex)
        }
    }

    private fun saveThumbnail(uri: Uri) {
//        val filePath = getAbsolutePathFromUri(uri) ?: return
        val filePath = uri.path ?: return
        val fileName = FILE_NAME_REGEX.find(filePath)?.value ?: "--"

        val thumbnail: Bitmap? = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            @Suppress("DEPRECATION")
            ThumbnailUtils.createVideoThumbnail(
                filePath,
                MediaStore.Video.Thumbnails.MINI_KIND
            )
        } else {
            ThumbnailUtils.createVideoThumbnail(
                uri.toFile(),
                Size(100, 100),
                null
            )
        }

//        val thumbnail: Bitmap? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
//            context?.contentResolver?.loadThumbnail(uri, Size(200, 200), null)
//        } else {
//            ThumbnailUtils.createVideoThumbnail(
//                uri.toFile(),
//                Size(100, 100),
//                null
//            )
//        }

//        val contentValues = ContentValues().apply {
//            put(
//                MediaStore.MediaColumns.DISPLAY_NAME,
//                "_$fileName.jpg"
//            )
//            put(
//                MediaStore.MediaColumns.RELATIVE_PATH,
//                Environment.DIRECTORY_DCIM + File.separator + "${getString(R.string.dhms)}/thumbnails"
//            )
//        }
//        val insertUri = context?.contentResolver?.insert(
//            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
//            contentValues
//        ) ?: return
//        val outputStream = context?.contentResolver?.openOutputStream(insertUri)
        val thumbnailFile = File((activity as MediaActivity).outputDirectory, "_$fileName.jpg")
        var outputStream: FileOutputStream? = null
        try {
            outputStream = FileOutputStream(thumbnailFile)
            thumbnail?.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
            outputStream.flush()
            videoThumbnail = Uri.fromFile(thumbnailFile)
        } catch (e: Exception) {
            Log.e(TAG, "Failed to save the thumbnail, $e")
        } finally {
            outputStream?.close()
        }
    }

    override fun onPause() {
        isVideoPrepared = false
        if (this::mediaPlayer.isInitialized) {
            if (!binding.isFailed) {
                binding.playBtn.visibility = View.VISIBLE
            }
            if (mediaPlayer.isPlaying) {
                mediaPlayer.pause()
            }
        } else if (binding.videoViewer.visibility == View.VISIBLE) {
            binding.photoViewer.visibility = View.VISIBLE
            if (!binding.isFailed) {
                binding.playBtn.visibility = View.VISIBLE
            }
            binding.videoViewer.pause()
        }
        super.onPause()
    }

    companion object {
        const val TAG = "PreviewFragment"

        private val FILE_NAME_REGEX = """(\d){4}(-(\d){2}){2}_((\d){2}-){2}(\d){2}""".toRegex()
    }
}